package sntp;

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.SocketAddress;
import java.text.DecimalFormat;
import org.simpleframework.xml.Root;
import org.xml.sax.SAXNotSupportedException;

/**
 * NtpClient - an NTP client for Java. This program connects to an NTP server
 * and prints the response to the console.
 * <p>
 * The local clock offset calculation is implemented according to the SNTP
 * algorithm specified in RFC 2030.
 * <p>
 * Note that on windows platforms, the curent time-of-day timestamp is limited
 * to an resolution of 10ms and adversely affects the accuracy of the results.
 * <p>
 * <p>
 * This code is copyright (c) Adam Buckley 2004
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version. A HTML version of the GNU General Public License can be
 * seen at http://www.gnu.org/licenses/gpl.html
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
 * more details.
 * <p>
 * @author Adam Buckley
 */
public class SntpClient implements ISNTPClient
{
	private static final double SecondsFromBeginOf20hCentury = 2208988800.0;
	private static final int SNTPPort = 123;
	private static double timeOffset;

	private static String[] serverAddresses;

	@Override
	public void Synchronize() throws IOException
	{
		for ( int i = 0; i < serverAddresses.length; ++i )
		{

			DatagramSocket socket = new DatagramSocket();
			byte[] buf = new NtpMessage().toByteArray();
			DatagramPacket packet
							= new DatagramPacket(buf, buf.length, InetAddress.getByName(serverAddresses[i]), SNTPPort);

			NtpMessage.encodeTimestamp(packet.getData(), 40,
																 (org.joda.time.DateTimeUtils.currentTimeMillis() / 1000.0) + SecondsFromBeginOf20hCentury);

			socket.send(packet);

			System.out.println("NTP request sent, waiting for response...\n");
			packet = new DatagramPacket(buf, buf.length);
			socket.receive(packet);

			//todo: timer?
			double destinationTimestamp
							= (org.joda.time.DateTimeUtils.currentTimeMillis() / 1000.0) + SecondsFromBeginOf20hCentury;

			NtpMessage msg = new NtpMessage(packet.getData());

			double roundTripDelay = (destinationTimestamp - msg.originateTimestamp)
							- (msg.transmitTimestamp - msg.receiveTimestamp);

			double localClockOffset
							= ((msg.receiveTimestamp - msg.originateTimestamp)
							+ (msg.transmitTimestamp - destinationTimestamp)) / 2;

			System.out.println("before change:" + org.joda.time.DateTime.now());
			timeOffset += localClockOffset;
			org.joda.time.DateTimeUtils.setCurrentMillisOffset(( long ) timeOffset);
			System.out.println("after change: " + org.joda.time.DateTime.now());

			System.out.println("NTP server: " + serverAddresses[i]);
			System.out.println(msg.toString());

			System.out.println("Dest. timestamp:     "
							+ NtpMessage.timestampToString(destinationTimestamp));

			System.out.println("Round-trip delay: "
							+ new DecimalFormat("0.00").format(roundTripDelay * 1000) + " ms");

			System.out.println("Local clock offset: "
							+ new DecimalFormat("0.00").format(localClockOffset * 1000) + " ms");

			System.out.println("Local timeOffset: "
							+ new DecimalFormat("0.00").format(timeOffset * 1000) + " ms");

			socket.close();
			//todo:if timer
			break;
		}
	}

	public SntpClient( SntpClientSettings settings )
	{
		this.timeOffset = 0.0;
		serverAddresses = settings.getAddresses();
	}

}
